package lumis.doui.source.postloadprocessor;

import lumis.doui.DouiContext;
import lumis.doui.hyperlink.DouiHyperlink;
import lumis.doui.source.ISourceData;
import lumis.doui.source.Source;
import lumis.doui.source.TabularData;
import lumis.portal.PortalException;
import lumis.portal.UnexpectedException;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.el.LumisExpressionEvaluatorImpl;
import lumis.portal.hyperlink.HyperLinkConfig;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.serviceinstance.ServiceInstanceConfig;
import lumis.portal.serviceinstance.acl.IServiceInstanceAclManager;
import lumis.portal.serviceinstance.acl.ServiceInstancePermissions;
import lumis.portal.serviceinterface.IServiceInterfaceUrl;
import lumis.util.ITransaction;
import lumis.util.XmlUtil;

import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.VariableResolver;

import org.w3c.dom.Node;

/**
 * Post Load Processor that generates a link for a field.
 *
 * @version $Revision: 11835 $ $Date: 2010-08-05 16:29:01 -0300 (Thu, 05 Aug 2010) $
 * @since 4.2.0
 */
public class RowLinkPostLoadProcessor implements IPostLoadProcessor
{
	private final LumisExpressionEvaluatorImpl evaluator = new LumisExpressionEvaluatorImpl();

	@SuppressWarnings("unchecked")
	public void processSource(SessionConfig sessionConfig, Source source, Node parametersNode, ITransaction transaction) throws PortalException
	{
		String fieldId = XmlUtil.readNodeString("fieldId", parametersNode);
		if(fieldId == null)
			throw new UnexpectedException("fieldId not specified for the RowLinkPostLoadProcessor");

		if(!checkPermissions(parametersNode, source))
			return;
		
		DouiContext douiContext = source.getDouiContext();
		DouiHyperlink douiHyperlink = douiContext.getDouiHyperlink();
		HyperLinkConfig hyperLinkConfig = douiHyperlink.getHyperLinkConfig(XmlUtil.selectSingleNode("hyperLink", parametersNode));
		
		IServiceInterfaceUrl url = ManagerFactory.getHyperLinkManager().getUrl(douiContext.getRequest().getSessionConfig(), hyperLinkConfig, douiContext.getTransaction());
		Node[] parameters = XmlUtil.selectNodes("addParameters/parameter", parametersNode);
		
		if(url != null)
		{
			// validate the preconditions if any
			Node precondition = XmlUtil.selectSingleNode("precondition", parametersNode);
			
			TabularData tabularData = (TabularData)source.getData();
			for(ISourceData row : tabularData.getRows())
			{
				VariableResolver variableResolver = new PostLoadProcessorVariableResolver(row, source);
				
				if(precondition != null)
				{
					String preconditionExpression = precondition.getTextContent();
					try
					{
						if(!((Boolean)evaluator.evaluate("${"+preconditionExpression+"}", Boolean.class, variableResolver, null)).booleanValue())
							continue;
					}
					catch (ELException e)
					{
						// ignore this EL exception. This expression may be processed at a later stage.
					}
				}
				
				for(Node parameter : parameters)
				{
					String name = XmlUtil.readAttributeString("name", parameter);
					String valueFieldId = XmlUtil.readAttributeString("valueFieldId", parameter, name);
					String value = row.get(valueFieldId, String.class);
					
					if(value == null)
						value = "";
					
					url.setParameter(name, value);
				}
				row.put(fieldId, url.toString());
			}
		}
	}

	public boolean checkPermissions(Node parametersNode, Source source) throws PortalException
	{
		boolean allowed = false;
		IServiceInstanceAclManager aclManager = ManagerFactory.getServiceInstanceAclManager();
		ServiceInstanceConfig serviceInstanceConfig = source.getDouiContext().getRequest().getServiceInstanceConfig();
		// if no service instance was provided, skip validation
		if (serviceInstanceConfig == null)
			return true;

		SessionConfig sessionConfig = source.getDouiContext().getRequest().getSessionConfig();

		ServiceInstancePermissions servicePermissions = aclManager.getPermissions(sessionConfig, serviceInstanceConfig.getServiceId(), source.getDouiContext().getTransaction());
		Node[] permissions = XmlUtil.selectNodes("permissions/permission", parametersNode);
		if (permissions.length > 0)
		{
			for (Node permission : permissions)
			{
				String permissionId = XmlUtil.readAttributeString("id", permission);
				if (aclManager.checkPermission(sessionConfig, serviceInstanceConfig.getId(), servicePermissions.valueOf(permissionId), source.getDouiContext().getTransaction()))
				{
					allowed = true;
					break;
				}
			}

			return allowed;
		}
		else
		{
			return true;
		}
	}

}
